Previous Page TOC Next Page


22 — Using the Windows 95 API

by David Medinets

This chapter will look at the Windows 95 API or Application Programming Interface. The Windows 95 API consists of a large number of functions that Microsoft has made available for you to use. Usually, an API function does something that is part of the operating system. For example, determining the display resolution or finding out how much memory is available.

Visual Basic wraps the Windows 95 API into an easy-to-program environment. When you display a command button, Visual Basic translates your requests into function calls to the API. Normally, you don't need to worry about what the API consists of.

Sometimes, however, Visual Basic does not allow you to use a specific operating system function call. When this happens, you need to call the API yourself. This chapter will show you how to do this.

API functions are located inside DLL files. A DLL, short for Dynamic Link Library, is a collection of functions located in a single file. Windows 95 knows how to find a specific function inside a DLL file. The Visual Basic Declare statement links the statement name with the DLL file and tells Visual Basic what parameters an API function needs and what type of data it returns, if any.

This chapter is not an exhaustive listing of the over 1,300 available Windows 95 API functions; instead, it will show you how some functions can be used in real-life situations. Table 22.1 lists the API functions mentioned in this chapter and the listing number in which the function is used. A copy of each listing has been included on the CD-ROM provided with this book.

API Function


Code Listing (Page Number)


Short Description


CloseHandle

Listing 22.6, p. 646

This function terminates a thread or process.

CreateFontIndirect

Listing 22.8, p. 651

This function creates a logical font that can be selected as the current font for any device.

CreateProcessA

Listing 22.6, p. 646

This function executes a given file starting a new process and thread. It is important to close both the thread and the process using the CloseHandle function.

DeleteObject

Listing 22.8, p. 651

This function frees all memory associated with an object. An object can be a font, pen, palette, and so on.

GetCurrentDirectory

Listing 22.3, p. 641

This function returns the current directory.

GetPrivateProfileInt

Listing 22.5, p. 643

This function returns an integer value from a private INI file.

GetPrivateProfileString

Listing 22.5, p. 643

This function returns a value from a private INI file.

GetProfileInt

Listing 22.5, p. 643

This function returns an integer value from the WIN.INI file.

GetProfileString

Listing 22.5, p. 643

This function returns a value from the WIN.INI file.

GetSystemDirectory

Listing 22.3, p. 641

The function returns the system subdirectory under the main Windows directory. The system directory contains such files as DLLs, drivers, and font files.

GetSystemMetrics

Listing 22.2, p. 639

This function returns the height and width of various Windows elements and the values of various system configuration values.

GetTempPath

Listing 22.3, p. 641

This function returns the directory Windows uses as temporary storage.

GetVersionEx

Listing 22.1, p. 638

This function returns information about the version number of Windows.

GetWindowsDirectory

Listing 22.3, p. 641

This function returns the directory in which Windows was installed.

GetWindowRect

Listing 22.4, p. 642

This function returns the corner coordinates of a given object.

hread

Listing 22.12, p. 659

This function reads blocks (can be > 64K) of data from files.

hwrite

Listing 22.12, p. 659

This function writes blocks (can be > 64K) of data to files.

lclose

Listing 22.12, p. 659

This function closes files.

LZClose

Listing 22.6, p. 646

This function closes files opened with the LZOpenFile function.

LZCopy

Listing 22.6, p. 646

This function copies a file opened with LZOpenFile.

LZOpenFile

Listing 22.6, p. 646

This function opens a file that might be compressed.

LZRead

Listing 22.6, p. 646

This function reads from a compressed file as if it were not compressed.

LZSeek

Listing 22.6, p. 646

This function positions the file pointer in a compressed file as if the file were not compressed.

OpenFile

Listing 22.12, p. 659

This function creates, opens, or deletes a file.

ReleaseCapture

Listing 22.11, p. 657

This function releases the mouse capture for the current thread and restores normal mouse input processing.

SelectObject

Listing 22.8, p. 651

This function selects an object for use in a given device context.

SetCapture

Listing 22.11, p. 657

This function allows the current thread to capture all mouse events.

SetCursorPos

Listing 22.4, p. 642

This function sets the mouse pointer position.

TextOut

Listing 22.8, p. 651

This function displays text using a given device context.

WaitForSingleObject

Listing 22.6, p. 646

This function waits for a process, thread, or object to get into a desired state.

WritePrivateProfileString

Listing 22.5, p. 643

This function writes an application/key value profile string to a private INI file.

WriteProfileString

Listing 22.5, p. 643

This function writes an application/key value profile string to the WIN.INI file.

API Functions Can Be Dangerous!

As you look at the examples in this chapter and explore the rest of the API, remember that some API functions are very dangerous. (For example, the menu API functions clash with Visual Basic.) Save your work often! If you have trouble, look at the following list for ideas:

Changes to API since Windows 3.1

Most of the changes to API are because of the need to support 32-bit operations. Many functions have been added to support the new functionality of the Windows 95 operating system. Additional OLE functionality has also been added. Following is a short list of changes that affect how API calls are made:

Tricks with Windows

The following sections are devoted to short topics that allow you to interact with the Windows operation system.

Getting System Version Information

Sometimes, it is nice to know the version of Windows your program is running in. The recommended method for doing this is to use the GetVersionEx API function. Listing 22.1 shows how to call the function. The main difference between GetVersionEx and the older GetVersion function is that the major and minor version numbers are split into separate structure members.

The GetVersionEx function also lets you determine which type of Windows platform your program is running on: Win32s, Windows, or Windows NT. Listing 22.1 shows you how to check for each platform type.

Option Explicit

Private Type OSVERSIONINFO

        dwOSVersionInfoSize As Long

        dwMajorVersion As Long

        dwMinorVersion As Long

        dwBuildNumber As Long

        dwPlatformId As Long

        szCSDVersion As String * 128

End Type

'  dwPlatformId defines:

Private Const VER_PLATFORM_WIN32s = 0

Private Const VER_PLATFORM_WIN32_WINDOWS = 1

Private Const VER_PLATFORM_WIN32_NT = 2

Private Declare Function GetVersionEx Lib "kernel32" _

    Alias "GetVersionExA" _

    (lpVersionInformation As OSVERSIONINFO) As Long

Private Sub Form_Load()

    Dim v As OSVERSIONINFO

    v.dwOSVersionInfoSize = Len(v)

    GetVersionEx v

    MsgBox "Major Version = " & v.dwMajorVersion

    MsgBox "Minor Version = " & v.dwMinorVersion

    MsgBox "Build Number = " & v.dwBuildNumber

    If v.dwPlatformId = VER_PLATFORM_WIN32s Then MsgBox "Win32s"

    If v.dwPlatformId = VER_PLATFORM_WIN32_WINDOWS Then MsgBox "Windows"

    If v.dwPlatformId = VER_PLATFORM_WIN32_NT Then MsgBox "Windows NT"

End Sub

Caution

The WIN32API.TXT file shows the GetVersionEx declaration with the lpVersionInformation parameter being passed as by value. This is incorrect; Visual Basic does not allow you to pass user-defined structures this way. Use the Declare statement as shown in Listing 22.1.

Getting System Information

Several API functions allow you to access information about the Windows system your program is running on. The program in Listing 22.2 prints out all the information available from the GetSystemMetrics function. There are 45 different pieces of information you can access using this one function.

Private Const SM_CXSCREEN = 0

Private Const SM_CYSCREEN = 1

Private Const SM_CXVSCROLL = 2

Private Const SM_CYHSCROLL = 3

Private Const SM_CYCAPTION = 4

Private Const SM_CXBORDER = 5

Private Const SM_CYBORDER = 6

Private Const SM_CXDLGFRAME = 7

Private Const SM_CYDLGFRAME = 8

Private Const SM_CYVTHUMB = 9

Private Const SM_CXHTHUMB = 10

Private Const SM_CXICON = 11

Private Const SM_CYICON = 12

Private Const SM_CXCURSOR = 13

Private Const SM_CYCURSOR = 14

Private Const SM_CYMENU = 15

Private Const SM_CXFULLSCREEN = 16

Private Const SM_CYFULLSCREEN = 17

Private Const SM_CYKANJIWINDOW = 18

Private Const SM_MOUSEPRESENT = 19

Private Const SM_CYVSCROLL = 20

Private Const SM_CXHSCROLL = 21

Private Const SM_DEBUG = 22

Private Const SM_SWAPBUTTON = 23

Private Const SM_RESERVED1 = 24

Private Const SM_RESERVED2 = 25

Private Const SM_RESERVED3 = 26

Private Const SM_RESERVED4 = 27

Private Const SM_CXMIN = 28

Private Const SM_CYMIN = 29

Private Const SM_CXSIZE = 30

Private Const SM_CYSIZE = 31

Private Const SM_CXFRAME = 32

Private Const SM_CYFRAME = 33

Private Const SM_CXMINTRACK = 34

Private Const SM_CYMINTRACK = 35

Private Const SM_CXDOUBLECLK = 36

Private Const SM_CYDOUBLECLK = 37

Private Const SM_CXICONSPACING = 38

Private Const SM_CYICONSPACING = 39

Private Const SM_MENUDROPALIGNMENT = 40

Private Const SM_PENWINDOWS = 41

Private Const SM_DBCSENABLED = 42

Private Const SM_CMOUSEBUTTONS = 43

Private Const SM_CMETRICS = 44

Private Declare Function GetSystemMetrics Lib "user32" _

    (ByVal nIndex As Long) As Long

Private Sub logMetric(nIndex As Long, name As String, desc As String)

    Dim ret As Long

    ret = GetSystemMetrics(nIndex)

    Printer.Print name; " = "; ret; Tab(30); "' "; desc

End Sub

Private Sub Form_Load()

    logMetric SM_CXSCREEN, "SM_CXSCREEN", "Screen width in pixels"

    logMetric SM_CYSCREEN, "SM_CYSCREEN", "Screen height in pixels"

    logMetric SM_CXVSCROLL, "SM_CXVSCROLL", "Vertical scroll arrow width"

    logMetric SM_CYHSCROLL, "SM_CYHSCROLL", "Horizontal scroll arrow height"

    logMetric SM_CYCAPTION, "SM_CYCAPTION", "Caption bar height"

    logMetric SM_CXBORDER, "SM_CXBORDER", "Window border width"

    logMetric SM_CYBORDER, "SM_CYBORDER", "Window border height"

    logMetric SM_CXDLGFRAME, "SM_CXDLGFRAME", "Dialog window frame width"

    logMetric SM_CYDLGFRAME, "SM_CYDLGFRAME", "Dialog window frame height"

    logMetric SM_CYVTHUMB, "SM_CYVTHUMB", "Vertical scroll thumb height"

    logMetric SM_CXHTHUMB, "SM_CXHTHUMB", "Horizontal scroll thumb width"

    logMetric SM_CXICON, "SM_CXICON", "Icon width"

    logMetric SM_CYICON, "SM_CYICON", "Icon height"

    logMetric SM_CXCURSOR, "SM_CXCURSOR", "Cursor width"

    logMetric SM_CYCURSOR, "SM_CYCURSOR", "Cursor height"

    logMetric SM_CYMENU, "SM_CYMENU", "Menu bar height"

    logMetric SM_CXFULLSCREEN, "SM_CXFULLSCREEN", "Full screen client area width"

    logMetric SM_CYFULLSCREEN, "SM_CYFULLSCREEN", "Full screen client area height"

    logMetric SM_CYKANJIWINDOW, "SM_CYKANJIWINDOW", "Kanji window height"

    logMetric SM_MOUSEPRESENT, "SM_MOUSEPRESENT", "Mouse present flag"

    logMetric SM_CYVSCROLL, "SM_CYVSCROLL", "Vertical scroll arrow height"

    logMetric SM_CXHSCROLL, "SM_CXHSCROLL", "Horizontal scroll arrow width"

    logMetric SM_DEBUG, "SM_DEBUG", "Debug version flag"

    logMetric SM_SWAPBUTTON, "SM_SWAPBUTTON", "Mouse buttons swapped flag"

    logMetric SM_RESERVED1, "SM_RESERVED1", "Reserved"

    logMetric SM_RESERVED2, "SM_RESERVED2", "Reserved"

    logMetric SM_RESERVED3, "SM_RESERVED3", "Reserved"

    logMetric SM_RESERVED4, "SM_RESERVED4", "Reserved"

    logMetric SM_CXMIN, "SM_CXMIN", "Minimum window width"

    logMetric SM_CYMIN, "SM_CYMIN", "Minimum window height"

    logMetric SM_CXSIZE, "SM_CXSIZE", "Minimize/Maximize icon width"

    logMetric SM_CYSIZE, "SM_CYSIZE", "Minimize/Maximize icon height"

    logMetric SM_CXFRAME, "SM_CXFRAME", "Window frame width"

    logMetric SM_CYFRAME, "SM_CYFRAME", "Window frame height"

    logMetric SM_CXMINTRACK, "SM_CXMINTRACK", "Minimum window tracking width"

    logMetric SM_CYMINTRACK, "SM_CYMINTRACK", "Minimum window tracking height"

    logMetric SM_CXDOUBLECLK, "SM_CXDOUBLECLK", "Double click x tolerance (3.1)"

    logMetric SM_CYDOUBLECLK, "SM_CYDOUBLECLK", "Double click y tolerance (3.1)"

    logMetric SM_CXICONSPACING, "SM_CXICONSPACING", "Horizontal icon spacing (3.1)"

    logMetric SM_CYICONSPACING, "SM_CYICONSPACING", "Vertical icon spacing (3.1)"

    logMetric SM_MENUDROPALIGNMENT, "SM_MENUDROPALIGNMENT", "Left or right menu drop (3.1)"

    logMetric SM_PENWINDOWS, "SM_PENWINDOWS", "Pen extensions installed (3.1)"

    logMetric SM_DBCSENABLED, "SM_DBCSENABLED", "DBCS version of USER32 installed"

    logMetric SM_CMOUSEBUTTONS, "SM_CMOUSEBUTTONS", "Number of buttons on mouse"

    logMetric SM_CMETRICS, "SM_CMETRICS", "SM_CMETRICS"

    Printer.NewPage

    Printer.EndDoc

End Sub

Using the GetSystemMetrics function is simple. All the action in Listing 22.2 occurs in the logMetric subroutine. This subroutine calls the GetSystemMetrics function and then prints the result to the Printer object. For more information about the Printer object, see Chapter 12, "Printing with Visual Basic."

You can also use the API to locate information about what directories Windows is using. For example, the GetWindowsDirectory API function lets you know the directory in which Windows was installed. Listing 22.3 shows how to use the four API functions that get information about the directories Windows is using.

Private Declare Function GetCurrentDirectory Lib "kernel32" _

        Alias "GetCurrentDirectoryA" (ByVal nBufferLength As Long, _

        ByVal lpBuffer As String) As Long

Private Declare Function GetSystemDirectory Lib "kernel32" _

    Alias "GetSystemDirectoryA" (ByVal lpBuffer As String, _

    ByVal nSize As Long) As Long

Private Declare Function GetTempPath Lib "kernel32" _

    Alias "GetTempPathA" (ByVal nBufferLength As Long, _

    ByVal lpBuffer As String) As Long

Private Declare Function GetWindowsDirectory Lib "kernel32" _

    Alias "GetWindowsDirectoryA" (ByVal lpBuffer As String, _

    ByVal nSize As Long) As Long

Private Sub Form_Load()

    Dim curDir As String

    Dim sysDir As String

    Dim tmpDir As String

    Dim winDir As String

    curDir = Space(500)

    sysDir = Space(500)

    tmpDir = Space(500)

    winDir = Space(500)

    curDir = Left(curDir, GetCurrentDirectory(Len(curDir), curDir))

    sysDir = Left(sysDir, GetSystemDirectory(sysDir, Len(sysDir)))

    tmpDir = Left(tmpDir, GetTempPath(Len(tmpDir), tmpDir))

    winDir = Left(winDir, GetWindowsDirectory(winDir, Len(winDir)))

    MsgBox curDir

    MsgBox sysDir

    MsgBox tmpDir

    MsgBox winDir

End Sub

Note

The Declare statement for the GetCurrentDirectory function in the WIN32API.TXT file.

Moving the Mouse Pointer

Occasionally, you find a feature in a program's user interface that you want to duplicate. This happened to me a little while ago: Every time a dialog box popped up, the mouse pointer was located on the most likely command button—a nifty feature. Although the WINAPI.TXT file (in the beta version of Visual Basic) does not have an entry for the SetCursorPos API function, the code in Listing 22.4 uses Windows 3.1 as a base to show how you can declare the SetCursorPos function.

To run the program in Listing 22.4, create a form with two command buttons. Then copy the code from the CD-ROM. After starting the program, click the first command button. The cursor should automatically move to the second command button.

Private Type POINTAPI

        x As Long

        y As Long

End Type

Private Type RECT

        left As Long

        top As Long

        Right As Long

        Bottom As Long

End Type

Private Declare Function SetCursorPos Lib "user32" _

    (ByVal x As Long, ByVal y As Long) As Long

Private Declare Function GetWindowRect Lib "user32" _

    (ByVal hwnd As Long, lpRect As RECT) As Long

Dim p As POINTAPI

Dim r As RECT

Dim rWidth As Long, rHeight As Long

Private Sub Command1_Click()

    GetWindowRect Command2.hwnd, r

    rWidth = r.Right - r.left

    rHeight = r.Bottom - r.top

    SetCursorPos r.left + (rWidth / 2), r.top + (rHeight / 2)

End Sub

The GetWindowRect function is called to get the screen coordinates of the corners of the second command button. The coordinates of the center of the button are then found and SetCursorPos is called.

Using Initialization Files

Windows 3.1 used initialization (INI) files to hold information used when Windows and other applications were started. INI files contained information such as the default printer, starting directories, and the last bookmark viewed in a file. In short, whatever information the program wanted to remember from one invocation to the next was stored in the INI file.

Microsoft no longer recommends the use of INI files because Windows 95—and Windows NT—use a System Registry to store initialization information. However, you still need to know about INI files to interact with Windows 3.1 programs and, perhaps, to read information from the WIN.INI file.

Although there are ten API functions that deal with INI files, this section discusses only six of them (three that work with the WIN.INI file and three that work with private or application INI files). Each of the functions is used in Listing 22.5 to show you how to interact with them.

The format of an INI file looks like this:

[VB Unleashed]                                    ' <== Section Name

Chapter Number = 22-Using the Windows 95 API.   ' <== Key Name & value

...

[next section]                                    ' <== Section Name

...

Each INI file is a series of section names and key names with their values.

Option Explicit

Private Declare Function GetProfileInt Lib "kernel32" _

    Alias "GetProfileIntA" (ByVal lpAppName As String, _

    ByVal lpKeyName As String, ByVal nDefault As Long) As Long

Private Declare Function GetProfileString Lib "kernel32" _

    Alias "GetProfileStringA" (ByVal lpAppName As String, _

    ByVal lpKeyName As String, ByVal lpDefault As String, _

    ByVal lpReturnedString As String, ByVal nSize As Long) As Long

Private Declare Function WriteProfileString Lib "kernel32" _

    Alias "WriteProfileStringA" (ByVal lpszSection As String, _

    ByVal lpszKeyName As String, ByVal lpszString As String) As Long

Private Declare Function GetPrivateProfileInt Lib "kernel32" _

    Alias "GetPrivateProfileIntA" (ByVal lpApplicationName As String, _

    ByVal lpKeyName As String, ByVal nDefault As Long, _

    ByVal lpFileName As String) As Long

Private Declare Function GetPrivateProfileString Lib "kernel32" _

    Alias "GetPrivateProfileStringA" (ByVal lpApplicationName As String, _

    ByVal lpKeyName As String, ByVal lpDefault As String, _

    ByVal lpReturnedString As String, ByVal nSize As Long, _

    ByVal lpFileName As String) As Long

Private Declare Function WritePrivateProfileString Lib "kernel32" _

    Alias "WritePrivateProfileStringA" _

    (ByVal lpApplicationName As String, ByVal lpKeyName As String, _

    ByVal lpString As String, ByVal lpFileName As String) As Long

Dim secName As String

Dim keyName As String

Dim prvName As String

Private Sub Form_Load()

    Dim keyValue As String

    secName = "VB Unleashed"

    keyName = "Chapter Number"

    prvName = "sams.ini"

    keyValue = "22-Using the Windows 95 APIs"

    testProfile

    WriteProfileString secName, keyName, keyValue

    testProfile

    WriteProfileString secName, keyName, ""

    testProfile

    testPrivateProfile

    WritePrivateProfileString secName, keyName, keyValue, prvName

    testPrivateProfile

    WritePrivateProfileString secName, keyName, "", prvName

    testPrivateProfile

End Sub

Private Sub testProfile()

    Dim lChapNum As Long

    Dim sChapNum As String

    lChapNum = GetProfileInt(secName, keyName, 10)

    sChapNum = Space(50)

    GetProfileString secName, keyName, "10", sChapNum, Len(sChapNum)

    MsgBox "Chapter Int = " & lChapNum

    MsgBox "Chapter Str = " & sChapNum

End Sub

Private Sub testPrivateProfile()

    Dim lChapNum As Long

    Dim sChapNum As String

    lChapNum = GetPrivateProfileInt(secName, keyName, 10, prvName)

    sChapNum = Space(50)

    GetPrivateProfileString secName, keyName, "10", sChapNum, Len(sChapNum), prvName

    MsgBox "Private Chapter Int = " & lChapNum

    MsgBox "Private Chapter Str = " & sChapNum

End Sub

Note

The Declare statement for GetPrivateProfileString in the WIN32API.TXT file has the lpKeyName parameter as Any. It should be declared as ByVal lpKeyName as String.

The Declare statement for WritePrivateProfileString in the WIN32API.TXT file has the lpString parameter as Any. It should be declared as ByVal lpString as String.

You can see that the functions for the WIN32API.TXT file and the private files parallel each other. The program in Listing 22.5 first calls the testProfile function. The testProfile function looks for a section called VB Unleashed and then for the key name Chapter Number in WIN.INI. These won't be found; therefore the default value of 10 is returned and displayed in a message box.

Next, the WriteProfileString function is called to create the section name, key name, and key values in the WIN.INI file. The testProfile function is called again to verify that the entries were correctly created.

Then the WriteProfileString function is called to delete the entries just added. And the testProfile function is called to verify that the entries were deleted.

The code performs the same operations using a private INI file called SAMS.INI. If the SAMS.INI file does not exist, the WritePrivateProfileString function creates it.

This section has not discussed the GetProfileSection, WriteProfileSection, GetPrivateProfileSection, or WritePrivateProfileSection API functions. However, if you want to explore their use, you will find the constant vbNullChar to be invaluable. To read or set an entire section of an INI file, the API function needs a series of NULL-terminated strings, with the last string terminated by two NULLs. You can append the vbNullChar constant directly to a string to represent the NULL character.

Using Compressed Files

One of the more intriguing sets of API functions are located in the LZ32 DLL file. This file contains the Windows decompression API functions. You can use these functions to decompress files that were compressed using the COMPRESS executable. All files whose extensions end in an underscore (for example, FIGHT.IN_) have been compressed. Usually, files are compressed to save room on a diskette; the files are expanded during application installation.

However, the LZ32 DLL library also contains two functions (lzseek and lzread) that allow you to manipulate a compressed file as if it were normal size. This means that you can use a compressed file to hold inventory parts and still use normal routines to extract the data. Unfortunately, the API function only lets you read from the compressed file. To create, modify, or insert information, you first must expand the file, then make the change and recompress the file.

Still, the ability to use compressed databases, even in a read-only fashion, is valuable. In addition, the compression can act as a rudimentary encryption. It is possible that only another programmer will catch on to the idea that the file has been compressed instead of encrypted.

Listing 22.6 shows the class definition of COMPRESSION. It has routines to compress, expand, and read a file. If you are entering the code by hand, set the class module Name to "Compression" and set its Public flag to TRUE.

Option Explicit

Private Const OF_READ = &H0

Private Const OF_CREATE = &H1000

Private Const OFS_MAXPATHNAME = 128

Private Const NORMAL_PRIORITY_CLASS = &H20&

Private Const INFINITE = -1&

' OpenFile() Structure

Private Type OFSTRUCT

        cBytes As Byte

        fFixedDisk As Byte

        nErrCode As Integer

        Reserved1 As Integer

        Reserved2 As Integer

        szPathName(OFS_MAXPATHNAME) As Byte

End Type

Private Type STARTUPINFO

    cb As Long

    lpReserved As String

    lpDesktop As String

    lpTitle As String

    dwX As Long

    dwY As Long

    dwXSize As Long

    dwYSize As Long

    dwXCountChars As Long

    dwYCountChars As Long

    dwFillAttribute As Long

    dwFlags As Long

    wShowWindow As Integer

    cbReserved2 As Integer

    lpReserved2 As Long

    hStdInput As Long

    hStdOutput As Long

    hStdError As Long

End Type

Private Type PROCESS_INFORMATION

    hProcess As Long

    hThread As Long

    dwProcessID As Long

    dwThreadID As Long

End Type

Private Declare Function WaitForSingleObject Lib "kernel32" (ByVal _

    hHandle As Long, ByVal dwMilliseconds As Long) As Long

Private Declare Function CreateProcessA Lib "kernel32" (ByVal _

    lpApplicationName As Long, ByVal lpCommandLine As String, ByVal _

    lpProcessAttributes As Long, ByVal lpThreadAttributes As Long, _

    ByVal bInheritHandles As Long, ByVal dwCreationFlags As Long, _

    ByVal lpEnvironment As Long, ByVal lpCurrentDirectory As Long, _

    lpStartupInfo As STARTUPINFO, lpProcessInformation As _

    PROCESS_INFORMATION) As Long

Private Declare Function CloseHandle Lib "kernel32" (ByVal _

    hObject As Long) As Long

Private Declare Function LZCopy Lib "lz32.dll" (ByVal _

    hfSource As Long, ByVal hfDest As Long) As Long

Private Declare Function LZOpenFile Lib "lz32.dll" Alias "LZOpenFileA" _

    (ByVal lpszFile As String, lpOf As OFSTRUCT, ByVal style As Long) _

    As Long

Private Declare Function LZSeek Lib "lz32.dll" (ByVal _

    hfFile As Long, ByVal lOffset As Long, ByVal nOrigin _

    As Long) As Long

Private Declare Function LZRead Lib "lz32.dll" (ByVal _

    hfFile As Long, ByVal lpvBuf As String, ByVal cbread _

    As Long) As Long

Private Declare Sub LZClose Lib "lz32.dll" (ByVal hfFile As Long)

Private expandedName As String

Private compressedName As String

Property Get fileName() As String

    fileName = expandedName

End Property

Property Let fileName(fName As String)

    expandedName = fName

End Property

Public Sub compress()

    Dim p As PROCESS_INFORMATION

    Dim s As STARTUPINFO

    Dim procStatus As Long

    ' Initialize the STARTUPINFO structure:

    s.cb = Len(s)

    ' Start the shelled application:

    ' make sure that close upon exit is checked.

    CreateProcessA 0&, "setupkit\compress -r " & expandedName, _

       0&, 0&, 1&, _

       NORMAL_PRIORITY_CLASS, 0&, 0&, s, p

    ' Wait for the shelled application to finish:

    WaitForSingleObject p.hProcess, INFINITE

    CloseHandle p.hThread

    CloseHandle p.hProcess

    compressedName = Left(expandedName, _

        Len(expandedName) - 1) & "_"

End Sub

Public Sub expand()

    Dim openStruct As OFSTRUCT

    hSource& = LZOpenFile(compressedName, openStruct, OF_READ)

    ' Note: Do not use expName$ you will get a access violation.

    ' take care to pre-allocate space.

    hDestination& = LZOpenFile(expandedName, openStruct, OF_CREATE)

    ret& = bytesOfDest = LZCopy(hSource&, hDestination&)

    LZClose hDestination&

    LZClose hSource&

End Sub

Public Sub read(recNum As Long, recLen As Long, recBuf As String)

    Dim openStruct As OFSTRUCT

    hSource& = LZOpenFile(compressedName, openStruct, OF_READ)

    LZSeek hSource&, recLen * (recNum - 1), 0

    LZRead hSource&, recBuf, recLen

    LZClose hSource&

End Sub

The compress function is interesting because it starts a subprocess with the COMPRESS executable. This subprocess is affected by the properties associated with the COMPRESS.EXE file (especially the close_window_on_exit flag), which you can view on the Program tab of the Properties dialog box). Figure 22.1 shows the Properties dialog box. Display this dialog box by opening the Windows Explorer program, locating the COMPRESS.EXE file in the setupkit subdirectory under the Visual Basic directory, right-clicking on the file, and selecting the Properties menu option. Then, click on the Program tab. You will see the Close_Window_on_Exit checkbox. Make sure that it is checked so that the window will close when the compress program is finished running.


Figure 22.1. The Properties dialog box for COMPRESS.EXE.

Listing 22.7 shows the program that uses the COMPRESSION class. It uses a form with two text boxes and two command buttons. Place the text boxes one above the other; place the buttons side by side.

When the program starts, only the button labeled Create Testfile is active. Pressing it makes the program create a test file of 26 fixed-length records in a file called TESTFILE.DAT. The file is then compressed. A message box displays, allowing you time to look at both the TEXTFILE.DAT file and the compressed version, TEXTFILE.DA_.

The next step is the deletion of the original data file; you are again prompted to check the files. After you click OK, the compressed file is expanded so that you can verify that the act of compression did not lose any data.

The final actions of the Create Testfile button are to activate the second button, deactivate itself, and read the first compressed record.

Option Explicit

Private Type Record ' Define user-defined type.

    ID As String * 3

    Name As String * 20

End Type

Dim MyRecord As Record

Dim recIdx As Long

Dim recBuf As String * 100

Dim F As New COMPRESSION

Private Sub Command1_Click()

    Dim idx As Long

    F.fileName = "testfile.dat"

    Open F.fileName For Random As #1 Len = Len(MyRecord)

    For idx = 0 To 25

        MyRecord.ID = CStr(idx) + 1

        MyRecord.Name = "*" & String(18, idx + Asc("A")) & "*"

        Put #1, , MyRecord

    Next idx

    Close #1

    F.compress

    MsgBox "textfile.dat has been compressed...Go Look! Then click OK."

    Kill "testfile.dat"

    MsgBox "testfile.dat has been deleted...Go Look! Then click OK."

    F.expand

    MsgBox "textfile.da_ has been expanded...Go Look! Then click OK."

    Command1.Enabled = False

    Command2.Enabled = True

    readRec

End Sub

Private Sub Command2_Click()

    If recIdx > 26 Then recIdx = 1

    readRec

End Sub

Private Sub Form_Load()

    Command1.Caption = "Create TestFile"

    Command2.Caption = "Next Record"

    Command2.Enabled = False

    recIdx = 1

End Sub

Private Sub readRec()

    F.read recIdx, Len(MyRecord), recBuf

    MyRecord.ID = Left(recBuf, 3)

    MyRecord.Name = Mid(recBuf, 4)

    Text1.text = MyRecord.ID

    Text2.text = MyRecord.Name

    recIdx = recIdx + 1

End Sub

When you click the Next Record button, the next record is read. If the end of the records are reached, the method cycles back to the first record.

The readRec method is at the heart of the record-reading activity. It uses the read method of the COMPRESSION class to fill a buffer with the data located at record number recIdx. Then the record buffer is parsed to fill the MyRecord structure.

Displaying Rotated Fonts

Visual Basic can display text only along the 0º axis, from left to right. It is sometimes useful to be able to display fonts in other orientations. For example, if text relates to several controls, you may want to display the related text vertically.

By using Windows 95 API functions, you can rotate fonts. The class module in Listing 22.8 defines the ROTATEFONT class. Its main function, dispText, displays text at any angle.

Option Explicit

Private Const OUT_DEFAULT_PRECIS = 0

Private Const OUT_STRING_PRECIS = 1

Private Const OUT_CHARACTER_PRECIS = 2

Private Const OUT_STROKE_PRECIS = 3

Private Const OUT_TT_PRECIS = 4

Private Const OUT_DEVICE_PRECIS = 5

Private Const OUT_RASTER_PRECIS = 6

Private Const OUT_TT_ONLY_PRECIS = 7

Private Const OUT_OUTLINE_PRECIS = 8

Private Const CLIP_DEFAULT_PRECIS = 0

Private Const CLIP_CHARACTER_PRECIS = 1

Private Const CLIP_STROKE_PRECIS = 2

Private Const CLIP_MASK = &HF

Private Const CLIP_LH_ANGLES = 16

Private Const CLIP_TT_ALWAYS = 32

Private Const CLIP_EMBEDDED = 128

Private Const DEFAULT_QUALITY = 0

Private Const DRAFT_QUALITY = 1

Private Const PROOF_QUALITY = 2

Private Const DEFAULT_PITCH = 0

Private Const FIXED_PITCH = 1

Private Const VARIABLE_PITCH = 2

Private Const ANSI_CHARSET = 0

Private Const DEFAULT_CHARSET = 1

Private Const SYMBOL_CHARSET = 2

Private Const SHIFTJIS_CHARSET = 128

Private Const HANGEUL_CHARSET = 129

Private Const CHINESEBIG5_CHARSET = 136

Private Const OEM_CHARSET = 255

' Font Families

'

Private Const FF_DONTCARE = 0    '  Don't care or don't know.

Private Const FF_ROMAN = 16      '  Variable stroke width, serifed.

' Times Roman, Century Schoolbook, etc.

Private Const FF_SWISS = 32      '  Variable stroke width, sans-serifed.

' Helvetica, Swiss, etc.

Private Const FF_MODERN = 48     '  Constant stroke width, serifed or sans-serifed.

' Pica, Elite, Courier, etc.

Private Const FF_SCRIPT = 64     '  Cursive, etc.

Private Const FF_DECORATIVE = 80 '  Old English, etc.

' Font Weights

Private Const FW_DONTCARE = 0

Private Const FW_THIN = 100

Private Const FW_EXTRALIGHT = 200

Private Const FW_LIGHT = 300

Private Const FW_NORMAL = 400

Private Const FW_MEDIUM = 500

Private Const FW_SEMIBOLD = 600

Private Const FW_BOLD = 700

Private Const FW_EXTRABOLD = 800

Private Const FW_HEAVY = 900

Private Type LOGFONT

        lfHeight As Long

        lfWidth As Long

        lfEscapement As Long

        lfOrientation As Long

        lfWeight As Long

        lfItalic As Byte

        lfUnderline As Byte

        lfStrikeOut As Byte

        lfCharSet As Byte

        lfOutPrecision As Byte

        lfClipPrecision As Byte

        lfQuality As Byte

        lfPitchAndFamily As Byte

        lfFaceName As String * 32

End Type

Private Declare Function CreateFontIndirect Lib "gdi32" _

    Alias "CreateFontIndirectA" (lpLogFont As LOGFONT) As Long

Private Declare Function SelectObject Lib "gdi32" _

    (ByVal hDC As Long, ByVal hObject As Long) As Long

Private Declare Function TextOut Lib "gdi32" Alias "TextOutA" _

    (ByVal hDC As Long, ByVal x As Long, ByVal y As Long, _

    ByVal lpString As String, ByVal nCount As Long) As Long

Private Declare Function DeleteObject Lib "gdi32" _

    (ByVal hObject As Long) As Long

Private font As LOGFONT

Private Sub Class_Initialize()

    font.lfHeight = 10

    font.lfWidth = 0

    font.lfEscapement = 0

    font.lfPitchAndFamily = FF_MODERN

    font.lfCharSet = ANSI_CHARSET

    font.lfQuality = PROOF_QUALITY

    font.lfWeight = FW_NORMAL

    font.lfFaceName = ""

End Sub

Public Sub setPointSize(ps As Long)

    font.lfHeight = ps

End Sub

Public Sub setAngle(angle As Long)

    font.lfEscapement = angle * 10

End Sub

Public Sub dispText(hDC As Long, text As String, x As Long, y As Long)

    Dim hFont As Long

    Dim hOldFont As Long

    hFont = CreateFontIndirect(font)

    hOldFont = SelectObject(hDC, hFont)

    TextOut hDC, x, y, text, Len(text)

    hFont = SelectObject(hDC, hOldFont)

    DeleteObject hFont

End Sub

Listing 22.8 has quite a few constants defined for controlling which font is used with the TextOut API function. Before looking at the listing in detail, look at the program that uses the ROTATEFONT class; see Listing 22.9. Figure 22.2 shows the results of this program.


Figure 22.2. The output of using the ROTATEFONT class, example 1.

Private Sub Form_Click()

    Dim font As New ROTATEFONT

    font.setPointSize 36

    font.setAngle 10

    font.dispText Form1.hDC, "Frank and Burgers", 10, 100

    font.setAngle 5

    font.dispText Form1.hDC, "Frank and Burgers", 10, 100

    font.setAngle -5

    font.dispText Form1.hDC, "Frank and Burgers", 10, 100

    font.setAngle -10

    font.dispText Form1.hDC, "Frank and Burgers", 10, 100

End Sub

This first example shows that you have to do several things to display rotated text. First, you must define a variable as New ROTATEFONT. Then you must set the PointSize and Angle. Finally, you call the dispText method to print the text. Notice that you can use negative angles as well as positive ones when specifying the axis to use.

It is important to note that the display functions are called from the Click method and not the Load method. If you place the same code in the Load method, nothing is displayed on the form because the form has not yet finished being initialized.

Example 2 in Listing 22.10 shows the effect of printing using all four points of the compass. Figure 22.3 shows the results of this small program.


Figure 22.3. The output of using the ROTATEFONT class, example 2.

Private Sub Form_Click()

    Dim font As New ROTATEFONT

    font.setPointSize 14

    font.setAngle 0

    font.dispText Form1.hDC, "Frank and Burgers", 200, 150

    font.setAngle 90

    font.dispText Form1.hDC, "Frank and Burgers", 200, 150

    font.setAngle 180

    font.dispText Form1.hDC, "Frank and Burgers", 200, 150

    font.setAngle 270

    font.dispText Form1.hDC, "Frank and Burgers", 200, 150

End Sub

Note

The ROTATEFONT class can used with any object for which you can obtain an hDC value. This includes Forms and PictureBox objects as well as the Printer object.

Now let's go back and look briefly at Listing 22.8, where the ROTATEFONT class was defined. To use the TextOut API function, Windows must know which font it should use to display the text. You can describe a logical font using the LOGFONT structure. A logical font can be thought of as a font description. When Windows actually needs to display the font, the best font available is used. Windows cannot choose a font to use until it knows which device will be used to display the text. The font selected for displaying on a monitor might be different from what is used to display the same logical font on a printer. Table 22.2 describes the different members of the LOGFONT structure.

Member Name


Description


lfHeight

This member specifies the height, in logical units, of the font. Windows will find the largest font that does not exceed lfHeight.

lfWidth

This member specifies the average width, in logical units, of characters in the font. If zero, Windows will use the aspect ratio of the device to determine the closest font match.

lfEscapement

This member specifies the angle, in tenths of a degree, relative to the bottom of the page. Not all devices support this ability.

lfOrientation

This member specifies the orientation, in tenths of a degree, of each character's base line relative to the bottom of the page. Not all devices support this ability.

lfWeight

The member specifies the weight of the font. Although any number from 0 to 1,000 is valid (constants starting with FW are supplied), only 400 for Normal weight and 700 for Bold is supported. Any value over 550 is displayed as bold.

lfItalic

This member, when set to TRUE, specifies an italicized font.

ifUnderline

This member, when set to TRUE, requests an underlined font.

lfStrikeout

This member, when set to TRUE, requests a font with a strikeout line.

lfCharSet

This member specifies the character set to be used for the font. ANSI_CHARSET, OEM_CHARSET, SYMBOL_CHARSET, and UNICODE_CHARSET are the currently defined values.

lfOutPrecision

This member specifies how closely the output must match the requested font. OUT_CHARACTER_PRECIS, OUT_DEFAULT_PRECIS, OUT_STRING_PRECIS, and OUT_STROKE_PRECIS are the defined values.

lfClipPrecision

This member specifies how to clip characters that display partially outside the clipping region. CLIP_CHARACTER_PRECIS, CLIP_DEFAULT_PRECIS, and CLIP_STROKE_PRECIS are the defined values.

lfQuality

This member specifies how carefully Windows is to be in matching the logical font to a physical font. DEFAULT_QUALITY, DRAFT_QUALITY, and PROOF_QUALITY are the defined values.

lfPitchAndFamily

This member specifies both the pitch and the family of the typeface. Typically, the values DEFAULT_PITCH, FIXED_PITCH, or VARIABLE_PITCH are ORed with FF_DECORATIVE, FF_DONTCARE, FF_MODERN, FF_ROMAN, FF_SCRIPT, or FF_SWISS.

lfFaceName

This member specifies the typeface of the font. If NULL, a default typeface is used.

The default values of the logical font are set in the Class_Initialize function in the ROTATEFONT class module. Functions are provided to allow the programmer to change the default characteristics. This implementation of rotated text is very primitive. No thought has been given to checking whether the device has the capability to display rotated text or to changing the orientation of text.

Displaying ToolTips

One of the most recent enhancements to the user interface is the ToolTip. A ToolTip is the little window that pops up when you hold the mouse cursor over an icon or menu item for more than a second or so.

To duplicate this feature in Visual Basic, you must be able to capture mouse events while the cursor is over an object. The SetCapture API function sends all mouse events to a window (specified by hWnd). It is important to remember that each Visual Basic control is considered a window so that each control can potentially issue the SetCapture function.

The SetCapture function captures all mouse events, even those for other processes. Therefore, it is important to call the ReleaseCapture API function when the mouse moves away from your window.

The code in Listing 22.11 shows how this is done. The following line is used to determine whether the mouse has moved away from the Command1 control:

If x > Command1.Width Or x < 0 Or y > Command1.Height Or y < 0 Then

The ReleaseCapture function is also called if the Command1 control is clicked.

The TOOLTIP form consists of two command buttons, one picture box, and a timer. These can be placed anywhere on the form. The appearance property of the picture box should be set to 0 to eliminate the 3-D effect. This must be done at design time.

Option Explicit

Private Declare Function SetCapture Lib "user32" _

    (ByVal hwnd As Long) As Long

Private Declare Function ReleaseCapture Lib "user32" () As Long

Private Sub Command1_Click()

    Timer1.Enabled = False

    ReleaseCapture

    Picture1.Visible = False

End Sub

Private Sub Command1_MouseMove(Button As Integer, _

    Shift As Integer, x As Single, y As Single)

    If x > Command1.Width Or x < 0 Or y > Command1.Height Or y < 0 Then

        Timer1.Enabled = False

        ReleaseCapture

        Picture1.Visible = False

    Else

        If Not Picture1.Visible Then

            Timer1.Enabled = True

            SetCapture Command1.hwnd

        End If

    End If

End Sub

Private Sub Form_Load()

    Picture1.BackColor = Form1.BackColor

    Picture1.Visible = False

    Timer1.Interval = 250

    Timer1.Enabled = False

End Sub

Private Sub Timer1_Timer()

    Dim font As New ROTATEFONT

    Dim hlpText As String

    hlpText = "Help me!"

    Picture1.Width = Picture1.TextWidth(hlpText) + 100

    Picture1.Height = Picture1.TextHeight(hlpText) + 100

    Picture1.TOP = Command1.TOP + Command1.Height + 20

    Picture1.Left = Command1.Left + (Command1.Width / 2)

    Picture1.Visible = True

    Picture1.Cls

    font.setPointSize 12

    font.dispText Picture1.hDC, hlpText, 2, 2

    Timer1.Enabled = False

End Sub

Note

This program requires the ROTATEFONT class module from Listing 22.8.

This code makes no pretense to be elegant. Everything is hard-coded to demonstrate the steps needed to display the ToolTip. To make real use of these concepts, create a control array and have one routine handle the ToolTips. You may want to store the help strings in a resource file or an array so that they can be easily changed as your program changes. In addition, you can make the picture box prettier by changing the font, background colors, or maybe displaying a "thought balloon" around the text.

Copying Large Files

This section shows how to use the OpenFile, hread, hwrite, and lclose API functions to copy files. Although you can use the FileCopy statement to copy files, the routine in Listing 22.12 is better for the following reasons:

Listing 22.12 includes two functions: firstCopy and additionalCopy. They are used in the following manner:

firstCopy "vb.gid", "vb.one"

additionalCopy "vb.two"

To use these routines in your own Visual Basic program, use the Insert | Module menu option to add a module to your project. Call this module HUGECOPY.BAS and then copy the code from the CD-ROM file for Listing 22.12.

When testing the routines, try copying smaller files first. If a problem develops, you will find out quicker.

' Constants with OpenFile API call.

Private Const OF_WRITE = &H1

Private Const OF_READ = &H0

Private Const OF_CREATE = &H1000

' Structure filled in by OpenFile API call.

Private Type OFSTRUCT

        cBytes As Byte

        fFixedDisk As Byte

        nErrCode As Integer

        Reserved1 As Integer

        Reserved2 As Integer

        szPathName(128) As Byte

End Type

' declarations for the API functions that this class uses.

Private Declare Function OpenFile Lib "kernel32" _

    (ByVal lpFileName As String, _

     lpReOpenBuff As OFSTRUCT, _

     ByVal wStyle As Long) As Long

Private Declare Function hread Lib "kernel32" Alias "_hread" _

    (ByVal hFile As Long, lpBuffer As Any, ByVal lBytes As Long) As Long

Private Declare Function hwrite Lib "kernel32" Alias "_hwrite" _

    (ByVal hFile As Long, ByVal lpBuffer As String, ByVal lBytes As Long) As Long

Private Declare Function lclose Lib "kernel32" Alias "_lclose" _

    (ByVal hFile As Long) As Long

Private inpOFS As OFSTRUCT

Private outOFS As OFSTRUCT

Private myBuf As String

Private size As Long

Public Sub firstCopy(inp As String, out As String)

    Dim hInp As Long

    Dim hOut As Long

    size = FileLen(inp)

    myBuf = String(size, "*")

    hInp = OpenFile(inp, inpOFS, OF_READ)

    hOut = OpenFile(out, outOFS, OF_CREATE Or OF_WRITE)

    If (hInp <> -1 And hOut <> -1) Then

        hread hInp, ByVal myBuf, size

        hwrite hOut, ByVal myBuf, size

    End If

    lclose hOut

    lclose hInp

End Sub

Public Sub additionalCopy(out As String)

    Dim hOut As Long

    hOut = OpenFile(out, outOFS, OF_CREATE Or OF_WRITE)

    If (hOut <> -1) Then

        hwrite hOut, ByVal myBuf, size

    End If

    lclose hOut

End Sub

This module is pretty simple. The only tricky points are that the size variable must be global to the module so that the additionalCopy function can see it and that the space function is used to allocate memory.

You can use the space function to read an entire database into memory. Then you can access it with the various string-manipulation functions (left, middle, right, and instr). In fact, searching a file for a phrase becomes much easier if the file is entirely in memory.

The following sections discuss the four API functions used by the HUGECOPY code module.

The OpenFile API Function

The OpenFile API function can be used to open, create, or delete a file; it can also be used to test for a file's existence. First, let's look at the syntax of the function; then you will see how to control which action it performs. The syntax is as follows:

Private Declare Function OpenFile Lib "kernel32"

    (ByVal lpFileName As String, _

     lpReOpenBuff As OFSTRUCT, _

     ByVal wStyle As Long) As Long

As you can see, the OpenFile function is located in the file KERNEL32.DLL, takes three parameters, and returns a long value. The return value is a file handle if a file was successfully opened or created. If the action to be performed was to check a file's existence or delete a file, the return value is irrelevant unless an error occurred. The return value is HFILE_ERROR (—1) if an error has occurred.

The parameter lpFileName is the name of the file on which the function is to perform an action.

The parameter lpReOpenBuff is the address of an OFSTRUCT structure that is to be valued by the OpenFile function. This structure, shown here, has only three interesting members:

Private Type OFSTRUCT

        cBytes As Byte

        fFixedDisk As Byte

        nErrCode As Integer

        Reserved1 As Integer

        Reserved2 As Integer

        szPathName(OFS_MAXPATHNAME) As Byte

End Type

The fFixedDisk member is set to nonzero if lpFileName is on a fixed disk. The szPathName member holds the full path of the file. The nErrCode member is set to the error code if the OpenFile action fails. Table 22.3 shows a list of the possible error codes that nErrCode can be set to. Some of the error codes in Table 22.3 do not directly relate to copying with the HUGECOPY module; however it is good to see the wide range of possible errors so that you can plan other uses for the OpenFile function.


Note

Comments have been added to Table 22.3 only where the Public Constant names are not clearly indicative of the error.

Constant Name


Value


Description


ERROR_INVALID_FUNCTION

1&


ERROR_FILE_NOT_FOUND

2&


ERROR_PATH_NOT_FOUND

3&


ERROR_TOO_MANY_OPEN_FILES

4&


ERROR_ACCESS_DENIED

5&


ERROR_INVALID_HANDLE

6&


ERROR_ARENA_TRASHED

7&

There was a problem with the storage control blocks.

ERROR_NOT_ENOUGH_MEMORY

8&

There was not enough storage space to process the action.

ERROR_INVALID_BLOCK

9&

The storage control block address was invalid.

ERROR_BAD_ENVIRONMENT

10&


ERROR_BAD_FORMAT

11&

An attempt was made to load a program with an incorrect format.

ERROR_INVALID_ACCESS

12&

The access code was invalid.

ERROR_INVALID_DATA

13&


ERROR_INVALID_DRIVE

15&

The system can't find the requested drive.

ERROR_CURRENT_DIRECTORY

16&

A directory that is attached to can't be deleted.

ERROR_NOT_SAME_DEVICE

17&

The system can only move a file from one directory to another on the same disk drive. You attempted to move a file to another disk drive.

ERROR_NO_MORE_FILES

18&


ERROR_WRITE_PROTECT

19&

The media on which the file was to be written or created is write-protected.

ERROR_BAD_UNIT

20&

The system can't find the requested device.

ERROR_NOT_READY

21&

The requested device is not ready.

ERROR_BAD_COMMAND

22&

The requested device does not understand the requested action.

ERROR_CRC

23&

The action caused a data error.

ERROR_BAD_LENGTH

24&

The requested command has the wrong length.

ERROR_SEEK

25&

The requested device could not find an area on the media it was searching.

ERROR_NOT_DOS_DISK

26&

The requested device could not be accessed.

ERROR_SECTOR_NOT_FOUND

27&

The requested device could not find a section on the media it was searching.

ERROR_OUT_OF_PAPER

28&

The printer is out of paper.

ERROR_WRITE_FAULT

29&

The system could not write to the requested device.

ERROR_READ_FAULT

30&

The system could not read from the requested device.

ERROR_GEN_FAILURE

31&

The requested device is not functioning.

ERROR_SHARING_VIOLATION

32&

The requested file is currently being used by another process.

ERROR_LOCK_VIOLATION

33&

The requested file is currently locked, in whole or part, by another process.

ERROR_WRONG_DISK

34&

The wrong floppy disk is in the drive. This error can occur when installing software from floppy disk.

ERROR_SHARING_BUFFER_EXCEEDED

36&

The system has too many shared files open and can't open another.

ERROR_NOT_SUPPORTED

50&

The system does not support the network request specified.

ERROR_REM_NOT_LIST

51&

The remote computer requested is not available.

ERROR_DUP_NAME

52&

A duplicate name exists on the network.

ERROR_BAD_NETPATH

53&

The requested network path was not found.

ERROR_NETWORK_BUSY

54&


ERROR_DEV_NOT_EXIST

55&

The requested network resource of device is no longer available.

ERROR_TOO_MANY_CMDS

56&

The network BIOS command limit has been reached.

ERROR_ADAP_HDW_ERR

57&

A network adapter hardware error has been detected.

ERROR_BAD_NET_RESP

58&

The requested server can't perform the action.

ERROR_UNEXP_NET_ERR

59&

An unexpected network error has occurred.

ERROR_BAD_REM_ADAP

60&

The remote adapter is not compatible.

ERROR_PRINTQ_FULL

61&

The printer queue is full.

ERROR_NO_SPOOL_SPACE

62&

The spooler has run out of space on the server for the queue.

ERROR_PRINT_CANCELLED

63&

The file that was waiting to be printed has been deleted.

ERROR_NETNAME_DELETED

64&

The requested network name is no longer available.

ERROR_NETWORK_ACCESS_DENIED

65&


ERROR_BAD_DEV_TYPE

66&

The network resource type is not correct.

ERROR_BAD_NET_NAME

67&

The requested network name can't be found.

ERROR_TOO_MANY_NAMES

68&

The name limit for the local network adapter card has been exceeded.

ERROR_TOO_MANY_SESS

69&

The network BIOS session limit has been exceeded.

ERROR_SHARING_PAUSED

70&

The remote server has been paused or is being started.

ERROR_REQ_NOT_ACCEP

71&

The network request was not accepted.

ERROR_REDIR_PAUSED

72&

The requested printer or device has been paused.

ERROR_FILE_EXISTS

80&


ERROR_CANNOT_MAKE

82&

The requested directory or file could not be created.

ERROR_FAIL_I24

83&

A failure has occurred during an interrupt 24 call.

ERROR_OUT_OF_STRUCTURES

84&

There is no storage space left in which to process this request.

ERROR_ALREADY_ASSIGNED

85&

The local device is already in use.

ERROR_INVALID_PASSWORD

86&

The network password was incorrect.

ERROR_INVALID_PARAMETER

87&


ERROR_NET_WRITE_FAULT

88&

A write fault has occurred on the network.

The last parameter of the OpenFile function is wStyle. It is used to tell OpenFile which actions to perform. The basic actions are OF_CREATE, OF_DELETE, OF_EXIST, OF_READ, OF_VERIFY, and OF_WRITE (see Table 22.4).

You can also use _ to modify the basic actions. For example, you can use OF_PROMPT to tell Visual Basic to prompt the user for a filename if the requested file is not found.

Constant Name


Value


Description


OF_READ

&H0

This flag opens the file for read access only.

OF_WRITE

&H1

This flag opens the file for write access only.

OF_READWRITE

&H2

This flag opens the file for read and write access.

OF_SHARE_COMPAT

&H0

This flag opens the file in compatibility mode, which allows any program on the same computer to open the file any number of times.

OF_SHARE_EXCLUSIVE

&H10

This flag opens the file and prevents other programs from either reading or writing the file.

OF_SHARE_DENY_WRITE

&H20

This flag opens the file and prevents other programs from writing to it.

OF_SHARE_DENY_READ

&H30

This flag opens the file and prevents other programs from reading from it.

OF_SHARE_DENY_NONE

&H40

This flag opens the file without denying other programs read or write access to the file.

OF_PARSE

&H100

This flag causes the system to fill the OFSTRUCT buffer with information.

OF_DELETE

&H200

This flag causes the file to be deleted.

OF_VERIFY

&H400

This flag causes the system to compare the date and time in the OFSTRUCT buffer with that of the file. The value HFILE_ERROR (—1) is returned if the time and date are different.

OF_CANCEL

&H800

This flag adds a Cancel button to the dialog box OF_PROMPT uses.

OF_CREATE

&H1000

This flag creates a new file. If the file already exists, it is overwritten.

OF_PROMPT

&H2000

This flag causes the system to display a dialog box if the named file does not exist. The dialog box asks the user to insert into drive A a disk that contains the file.

OF_EXIST

&H4000

This flag opens the file and then closes it to see whether the file exists. It does not change the last-modified date of the file.

OF_REOPEN

&H8000

This flag opens the file using the information in the OFSTRUCT buffer.

The system looks for the file using the following search criteria:

  1. The current directory.

  2. The Windows directory (the directory containing WIN.COM), whose path the GetWindowsDirectory function retrieves.

  3. The Windows system directory (the directory containing such system files as GDI.EXE), whose path the GetSystemDirectory function retrieves.

  4. The directory containing the executable file for the current task; the GetModuleFileName function obtains the path of this directory.

  5. The directories listed in the PATH environment variable.

  6. The list of directories mapped in a network.

The hread API Function

The hread API function is used to read data from an open file into a buffer in memory. It can handle blocks of data greater than 64K. The syntax is as follows:

Private Declare Function hread Lib "kernel32" Alias "_hread" _

    (ByVal hFile As Long, lpBuffer As Any, ByVal lBytes As Long) As Long

The hread function is located in the KERNEL32.DLL file, takes three parameters, and returns a long value. The return value is the number of bytes read or HFILE_ERROR (—1).

The hFile parameter is the file handle of an open file. In the example in Listing 22.12, the handle was the return value of the OpenFile function.

The lpBuffer parameter is the location of a buffer to receive the data from the file. Make sure that the buffer is initialized before this function is called.

The lBytes parameter is the number of bytes of data to read. If the return value is less that lBytes, the end of the file was reached before all of the requested data was read.

The hwrite API Function

The hread API function is used to read data from an open file into a buffer in memory. It can handle blocks of data greater than 64K. The syntax is as follows:

Private Declare Function hwrite Lib "kernel32" Alias "_hwrite" _

    (ByVal hFile As Long, ByVal lpBuffer As String, ByVal lBytes As Long) As Long

The hwrite function is located in the KERNEL32.DLL file, takes three parameters, and returns a long value. The return value is the number of bytes written or HFILE_ERROR (—1).

The hFile parameter is the file handle of an open file. In the example in Listing 22.12, the handle was the return value of the OpenFile function.

The lpBuffer parameter is the location of the buffer whose contents are to be written to the file.

The lBytes parameter is the number of bytes of data to write.

The lclose API Function

The lclose API function is used to close an open file. Its syntax is as follows:

Private Declare Function lclose Lib "kernel32" Alias "_lclose" _

    (ByVal hFile As Long) As Long

The lclose function is located in the KERNEL32.DLL file, takes one argument, and returns a long value. The return value is zero for successful completion or HFILE_ERROR (—1) if the system could not close the file.

Summary

This chapter covered many different types of API functions. And yet, in reality, it barely scratched the surface of the functionality available to you with the Windows API library.

One piece of advice: before looking for a solution using an API function, either look for a way that Visual Basic can perform the task (you may have overlooked something in the manuals) or see whether an existing OCX can perform the task for you. Spending time debugging API calls can be frustrating and takes away time from your main programming task.

Previous Page TOC Next Page